// File:    node.cpp
// Author:  Brian Vanderburg II
// Purpose: Expression node
//------------------------------------------------------------------------------


// Includes
#include <new>
#include <memory>
#include <cmath>
#include <cerrno>

#include "COMMON/expr/node.h"
#include "COMMON/expr/expr.h"
#include "COMMON/expr/vallist.h"
#include "COMMON/expr/funclist.h"
#include "COMMON/expr/error.h"
#include "COMMON/expr/defs.h"

namespace ExprEval
{

// Node
//------------------------------------------------------------------------------

// Constructor
Node::Node (Expression *expr) : m_expr(expr)
{
    if(expr == 0)
    {
        SHOW_FATAL_ERROR("Null Point of Node::Node");
    }
}

// Destructor
Node::~Node()
{}

// Evaluate
double Node::Evaluate (ErrorInfo& errors) const
{
    //m_expr->TestAbort();

    return DoEvaluate (errors);
}

std::pair<double, double> Node::Evaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    //m_expr->TestAbort();

    return DoEvaluate (var_symbol, errors);
}

std::pair<double, double> Node::Evaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    //m_expr->TestAbort();

    return DoEvaluate (var_symbol_1, var_symbol_2, errors);
}
// Function node
//------------------------------------------------------------------------------

// Constructor
FunctionNode::FunctionNode (Expression *expr) : Node (expr),
    m_argMin (0), m_argMax(0), m_refMin (0), m_refMax(0)
{}

// Destructor
FunctionNode::~FunctionNode()
{
    // Delete child nodes
    std::vector<Node*>::size_type pos;

    for (pos = 0; pos < m_nodes.size(); pos++)
    {
        delete m_nodes[pos];
    }
}

// Get name
std::string FunctionNode::GetName() const
{
    return m_factory->GetName();
}

// Set argument count
void FunctionNode::SetArgumentCount (long argMin, long argMax, long refMin, long refMax)
{
    m_argMin = argMin;
    m_argMax = argMax;
    m_refMin = refMin;
    m_refMax = refMax;
}

// Parse expression
void FunctionNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool& good_parse)
{
    (void)v1;
    Parser::size_type pos, last;
    int plevel = 0;

    // Sanity check (start/end are function parenthesis)
    if(start >= end)
    {
        SHOW_NONFATAL_ERROR("syntax error");
        good_parse=false;
        return;
    }

    // Look
    last = start + 1;
    for (pos = start + 1; pos <= end && start + 1 != end; pos++)
    {
        switch(parser[pos].GetType())
        {
        case Token::TypeOpenParenthesis:
            {
                plevel++;
                break;
            };

        case Token::TypeComma:
        case Token::TypeCloseParenthesis:
            {
                // Handle Close parenthesis for all but the last one at the end
                if(parser[pos].GetType() == Token::TypeCloseParenthesis && pos != end)
                {
                    plevel--;

                    if(plevel < 0)
                    {
                        SHOW_NONFATAL_ERROR("unmatched parenthesis");
                        good_parse=false;
                        return;
                    }

                    break;
                }

                // Handle comma, or if it was the ending parenthesis treat it like comma
                if(plevel == 0)
                {
                    if(pos > last)
                    {
                        // reference parameter?
                        if(parser[last].GetType() == Token::TypeAmpersand)
                        {
                            // Reference parameter, check position and type of next parameter
                            if(last == pos - 2 && parser[last + 1].GetType() == Token::TypeIdentifier)
                            {
                                // Get value list
                                ValueList *vlist = m_expr->GetValueList();
                                if(vlist == 0)
                                {
                                    SHOW_NONFATAL_ERROR("No value list");
                                    good_parse=false;
                                    return;
                                }

                                // Get name
                                std::string ident = parser[last + 1].GetIdentifier();

                                // Make sure it is not a constant
                                if(vlist->IsConstant (ident))
                                {
                                    SHOW_NONFATAL_ERROR("constant reference");
                                    good_parse=false;
                                    return;
                                }

                                // Get address
                                double *vaddr = vlist->GetAddress (ident);
                                if(vaddr == 0)
                                {
                                    // Try to add it and get again
                                    vlist->Add (ident);
                                    vaddr = vlist->GetAddress (ident);
                                }

                                if(vaddr == 0)
                                {
                                    SHOW_NONFATAL_ERROR("not found");

                                    good_parse=false;
                                    return;
                                }

                                // Add it
                                m_refs.push_back(vaddr);
                            }
                            else
                            {
                                SHOW_NONFATAL_ERROR("syntax error");

                                good_parse=false;
                                return;
                            }
                        } // TypeAmpersand
                        else
                        {
                            // Create node
                            std::auto_ptr<Node> n (parser.ParseRegion (last, pos - 1, good_parse));
                            m_nodes.push_back(n.get());
                            n.release();
                        }
                    }
                    else
                    {
                        good_parse=false;
                        SHOW_NONFATAL_ERROR("unrecognized syntax in function of \"" <<this->GetName() << "\"" << std::endl);
                        return;
                    }

                    last = pos + 1;
                }

                break;
            }
        default:
            {
                break;
            }


        }
    }

    // plevel should be zero
    if(plevel != 0)
    {
        SHOW_NONFATAL_ERROR("unmatched parenthesis");

        good_parse=false;
        return;
    }


    // Check argument count
    if(m_argMin != -1 && m_nodes.size() < (std::vector<Node*>::size_type)m_argMin)
    {
        SHOW_NONFATAL_ERROR("invalid argument count of \"" <<GetName() << "\"");

        good_parse=false;
        return;
    }

    if(m_argMax != -1 && m_nodes.size() > (std::vector<Node*>::size_type)m_argMax)
    {
        SHOW_NONFATAL_ERROR("invalid argument count of \"" <<GetName() << "\"");

        good_parse=false;
        return;
    }

    if(m_refMin != -1 && m_refs.size() < (std::vector<double*>::size_type)m_refMin)
    {
        SHOW_NONFATAL_ERROR("invalid argument count of \"" <<GetName() << "\"");

        good_parse=false;
        return;
    }

    if(m_refMax != -1 && m_refs.size() > (std::vector<double*>::size_type)m_refMax)
    {
        SHOW_NONFATAL_ERROR("invalid argument count of \"" <<GetName() << "\"");

        good_parse=false;
        return;
    }
}

// Multi node
//------------------------------------------------------------------------------

// Constructor
MultiNode::MultiNode (Expression *expr) : Node (expr)
{}

// Destructor
MultiNode::~MultiNode()
{
    // Free child nodes
    std::vector<Node*>::size_type pos;

    for (pos = 0; pos < m_nodes.size(); pos++)
    {
        delete m_nodes[pos];
    }
}

// Evaluate
double MultiNode::DoEvaluate (ErrorInfo& errors) const
{
    std::vector<Node*>::size_type pos;
    double result = 0.0;

    for (pos = 0; pos < m_nodes.size(); pos++)
    {
        result = m_nodes[pos]->Evaluate (errors);
    }

    return result;
}



std::pair<double, double> MultiNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    SHOW_FATAL_ERROR("multi expressions is not supported in expression evaluate");
    (void)var_symbol;
    (void)errors;
    return std::make_pair (0., 0.);
}



std::pair<double, double> MultiNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    SHOW_FATAL_ERROR("multi expressions is not supported in expression evaluate");
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    return std::make_pair (0., 0.);
}


// Parse
void MultiNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    (void)v1;
    Parser::size_type pos, last;
    int plevel = 0;

    // Sanity check
    if(start >= end)
    {
        SHOW_NONFATAL_ERROR("syntax error");
        good_parse=false;
        return;
    }

    // Look
    last = start;
    for (pos = start; pos <= end; pos++)
    {
        switch(parser[pos].GetType())
        {
        case Token::TypeOpenParenthesis:
            {
                plevel++;
                break;
            };

        case Token::TypeCloseParenthesis:
            {
                plevel--;

                if(plevel < 0)
                {
                    SHOW_NONFATAL_ERROR("unmatched parenthesis");
                    good_parse=false;
                    return;
                }

                break;
            }

        case Token::TypeSemicolon:
            {
                if(plevel == 0)
                {
                    if(pos > last)
                    {
                        // Everything from last to pos - 1
                        std::auto_ptr<Node> n (parser.ParseRegion (last, pos - 1, good_parse));
                        m_nodes.push_back(n.get());
                        n.release();
                    }
                    else
                    {
                        SHOW_NONFATAL_ERROR("syntax error");

                        good_parse=false;
                        return;
                    }

                    last = pos + 1;
                }

                break;
            }
        default:
            {
                break;
            }
        }
    }

    // plevel should be zero
    if(plevel != 0)
    {
        SHOW_NONFATAL_ERROR("unmatched parenthesis");

        good_parse=false;
        return;
    }

    // If the end was not a semicolon, test it as well
    if(last < end + 1)
    {
        std::auto_ptr<Node> n (parser.ParseRegion (last, end, good_parse));
        m_nodes.push_back(n.get());
        n.release();
    }
}

std::string
MultiNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    (void)var_map_name;
    return "NOT finished";
}

// Assign node
//------------------------------------------------------------------------------

// Constructor
AssignNode::AssignNode (Expression *expr) : Node (expr), m_var(0), m_rhs (0)
{}

// Destructor
AssignNode::~AssignNode()
{
    // Free child node
    delete m_rhs;
}

// Evaluate
double AssignNode::DoEvaluate (ErrorInfo& errors) const
{
    return (*m_var = m_rhs->Evaluate (errors));
}



std::pair<double, double> AssignNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    SHOW_FATAL_ERROR("Assign operator is not supported in expression evaluate");
    (void)var_symbol;
    (void)errors;
    return std::make_pair (0., 0.);
}



std::pair<double, double> AssignNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    SHOW_FATAL_ERROR("Assign operator is not supported in expression evaluate");
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    return std::make_pair (0., 0.);
}


// Parse
void AssignNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 != start + 1 || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '='");
        good_parse=false;
        return;
    }

    // Get the value list
    ValueList *vlist = m_expr->GetValueList();
    if(vlist == 0)
    {
        SHOW_NONFATAL_ERROR("no value list");

        good_parse=false;
        return;
    }

    // Determine variable name
    std::string ident = parser[start].GetIdentifier();

    // Make sure it is not a constant
    if(vlist->IsConstant (ident))
    {
        SHOW_NONFATAL_ERROR("constant assign");

        good_parse=false;
        return;
    }

    // Get address
    double *vaddr = vlist->GetAddress (ident);

    if(vaddr == 0)
    {
        // If it does not already exist, try to create it
        vlist->Add (ident);
        vaddr = vlist->GetAddress (ident);
    }

    if(vaddr == 0)
    {
        SHOW_NONFATAL_ERROR("not found");

        good_parse=false;
        return;
    }

    // Parse the node (will throw if it can not parse)
    std::auto_ptr<Node> n (parser.ParseRegion (v1 + 1, end, good_parse));

    // Set data
    m_var = vaddr;
    m_rhs = n.release();
}

std::string
AssignNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("= (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}


// Add node
//------------------------------------------------------------------------------

// Constructor
AddNode::AddNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
AddNode::~AddNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double AddNode::DoEvaluate (ErrorInfo& errors) const
{
    return m_lhs->Evaluate (errors) + m_rhs->Evaluate (errors);
}



std::pair<double, double> AddNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol, errors);

    return std::make_pair (lhs.first+rhs.first, lhs.second+rhs.second);
}



std::pair<double, double> AddNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);

    return std::make_pair (lhs.first+rhs.first, lhs.second+rhs.second);
}


// Parse
void AddNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("syntax error");

        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
AddNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") + (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Subtract node
//------------------------------------------------------------------------------

// Constructor
SubtractNode::SubtractNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
SubtractNode::~SubtractNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double SubtractNode::DoEvaluate (ErrorInfo& errors) const
{
    return m_lhs->Evaluate (errors) - m_rhs->Evaluate (errors);
}



std::pair<double, double> SubtractNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol, errors);

    return std::make_pair (lhs.first-rhs.first, lhs.second-rhs.second);
}



std::pair<double, double> SubtractNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);

    return std::make_pair (lhs.first-rhs.first, lhs.second-rhs.second);
}

// Parse
void SubtractNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '-'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
SubtractNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") - (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Multiply node
//------------------------------------------------------------------------------

// Constructor
MultiplyNode::MultiplyNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
MultiplyNode::~MultiplyNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double MultiplyNode::DoEvaluate (ErrorInfo& errors) const
{
    return m_lhs->Evaluate (errors) * m_rhs->Evaluate (errors);
}



std::pair<double, double> MultiplyNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    /*
     * h=f*g ==> dh/dx = df/dx*g+f*dg/dx
     */
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol, errors);
    return std::make_pair (lhs.first*rhs.first, lhs.first*rhs.second+lhs.second*rhs.first);
}



std::pair<double, double> MultiplyNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    /*
     * h=f*g ==> d^2h/dxdy = d^2f/dxdy*g+df/dx*dg/dy+df/dy*dg/dx+f*d^2/dxdy
     */
    std::pair<double, double> lhs_2  = m_lhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> lhs_11 = m_lhs->Evaluate (var_symbol_1, errors);
    std::pair<double, double> lhs_12 = m_lhs->Evaluate (var_symbol_2, errors);

    std::pair<double, double> rhs_2  = m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> rhs_11 = m_rhs->Evaluate (var_symbol_1, errors);
    std::pair<double, double> rhs_12 = m_rhs->Evaluate (var_symbol_2, errors);
    const double lhs = lhs_2.first;
    const double rhs = rhs_2.first;

    const double der_value = lhs_2.second*rhs+lhs_11.second*rhs_12.second+lhs_12.second*rhs_11.second+lhs*rhs_2.second;

    return std::make_pair (lhs*rhs, der_value);
}

// Parse
void MultiplyNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '*'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
MultiplyNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") * (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Divide node
//------------------------------------------------------------------------------

// Constructor
DivideNode::DivideNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
DivideNode::~DivideNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double DivideNode::DoEvaluate (ErrorInfo& errors) const
{
    double r2 = m_rhs->Evaluate (errors);

    if(!equal_eps (r2, 0.0))
    {
        return m_lhs->Evaluate (errors) / r2;
    }
    else
    {
        SHOW_NONFATAL_ERROR("devided by zero");
        return INF_VALUE;
    }
}



std::pair<double, double> DivideNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    std::pair<double, double> lhs=m_lhs->Evaluate (var_symbol, errors);
    std::pair<double, double> rhs=m_rhs->Evaluate (var_symbol, errors);

    if(equal_eps (rhs.first, 0.))
    {
        SHOW_NONFATAL_ERROR("devided by zero");
        return std::make_pair (INF_VALUE, INF_VALUE);
    }

    /*
     * if h=f/g ==> dh/dx = (df/dx*g-f*dg/dx)/g^2
     */
    double val = lhs.first/rhs.first;
    double dval= (lhs.second*rhs.first-lhs.first*rhs.second)/(rhs.first*rhs.first);

    return std::make_pair (val, dval);
}



std::pair<double, double> DivideNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    /*
     * if h=f/g ==>dh/dx = (df/dx*g-f*dg/dx)/g^2
     * ==> d^2h/dxdy = d/dy ((df/dx*g-f*dg/dx)/g^2)
     * = (1/g)*d^2f/dxdy - (1/g^2)*df/dx*dg/dy - (1/g^2)df/dy*dg/dx - f/g^2*d^2g/dxdy + 2f/g^3*dg/dx*dg/dy
     */
    std::pair<double, double> lhs_2  = m_lhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> lhs_11 = m_lhs->Evaluate (var_symbol_1, errors);
    std::pair<double, double> lhs_12 = m_lhs->Evaluate (var_symbol_2, errors);
    const double lhs = lhs_2.first;

    std::pair<double, double> rhs_2  = m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    std::pair<double, double> rhs_11 = m_rhs->Evaluate (var_symbol_1, errors);
    std::pair<double, double> rhs_12 = m_rhs->Evaluate (var_symbol_2, errors);
    const double rhs = rhs_2.first;

    if(equal_eps (rhs, 0.))
    {
        SHOW_NONFATAL_ERROR("devided by zero");
        return std::make_pair (INF_VALUE, INF_VALUE);
    }

    const double g_1  = 1./rhs;
    const double g_2  = g_1*g_1;
    const double g_3  = g_2*g_1;
    const double val  = lhs*g_1;

    /*
     * d^2h/dxdy = (1/g)*d^2f/dxdy - (1/g^2)*df/dx*dg/dy - (1/g^2)df/dy*dg/dx - (f/g^2)d^2g/dxdy + 2f/g^3*dg/dx*dg/dy
     */
    const double dval =  g_1        * lhs_2.second                 // (1/g)d^2f/dxdy
                         -g_2        * lhs_11.second*rhs_12.second  // -(1/g^2)df/dx*dg/dy
                         -g_2        * lhs_12.second*rhs_11.second  // -(1/g^2)df/dy*dg/dx
                         -lhs*g_2    * rhs_2.second                 // -(f/g^2)d^2g/dxdy
                         +2.*lhs*g_3 * rhs_11.second*rhs_12.second; // 2f/g^3*dg/dx*dg/dy

    return std::make_pair (val, dval);
}

// Parse
void DivideNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '/'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
DivideNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") / (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// GT node
//------------------------------------------------------------------------------

// Constructor
GTNode::GTNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
GTNode::~GTNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double GTNode::DoEvaluate (ErrorInfo& errors) const
{
    return ((m_lhs->Evaluate (errors)>m_rhs->Evaluate (errors))?1.:0.);
}

std::pair<double, double> GTNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'>' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> GTNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'>' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void GTNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '>'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
GTNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") > (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// GE node
//------------------------------------------------------------------------------

// Constructor
GENode::GENode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
GENode::~GENode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double GENode::DoEvaluate (ErrorInfo& errors) const
{
    return ((m_lhs->Evaluate (errors)>=m_rhs->Evaluate (errors))?1.:0.);
}

std::pair<double, double> GENode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'>=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> GENode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'>=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void GENode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '>='");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
GENode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") >= (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// LT node
//------------------------------------------------------------------------------

// Constructor
LTNode::LTNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
LTNode::~LTNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double LTNode::DoEvaluate (ErrorInfo& errors) const
{
    return ((m_lhs->Evaluate (errors)<m_rhs->Evaluate (errors))?1.:0.);
}

std::pair<double, double> LTNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'<' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> LTNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'<' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void LTNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '<'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
LTNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") < (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// LE node
//------------------------------------------------------------------------------

// Constructor
LENode::LENode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
LENode::~LENode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double LENode::DoEvaluate (ErrorInfo& errors) const
{
    return ((m_lhs->Evaluate (errors)<=m_rhs->Evaluate (errors))?1.:0.);
}

std::pair<double, double> LENode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'<=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> LENode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'<=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void LENode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '<='");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
LENode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") <= (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// EQ node
//------------------------------------------------------------------------------

// Constructor
EQNode::EQNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
EQNode::~EQNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double EQNode::DoEvaluate (ErrorInfo& errors) const
{
    return ((equal_eps (m_lhs->Evaluate (errors), m_rhs->Evaluate (errors)))?1.:0.);
}

std::pair<double, double> EQNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'==' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> EQNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'==' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void EQNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '=='");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
EQNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") == (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// NE node
//------------------------------------------------------------------------------

// Constructor
NENode::NENode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
NENode::~NENode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double NENode::DoEvaluate (ErrorInfo& errors) const
{
    return ((!equal_eps (m_lhs->Evaluate (errors), m_rhs->Evaluate (errors)))?1.:0.);
}

std::pair<double, double> NENode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'!=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> NENode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'!=' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void NENode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '!='");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
NENode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") != (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// And node
//------------------------------------------------------------------------------

// Constructor
AndNode::AndNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
AndNode::~AndNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double AndNode::DoEvaluate (ErrorInfo& errors) const
{
    const bool lhs=equal_eps (m_lhs->Evaluate (errors), 0)?false:true;
    const bool rhs=equal_eps (m_rhs->Evaluate (errors), 0)?false:true;
    return ((lhs && rhs)?1.:0.);
}

std::pair<double, double> AndNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'&&' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> AndNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'&&' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void AndNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '&&'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
AndNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") && (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Or node
//------------------------------------------------------------------------------

// Constructor
OrNode::OrNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
OrNode::~OrNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double OrNode::DoEvaluate (ErrorInfo& errors) const
{
    const bool lhs=equal_eps (m_lhs->Evaluate (errors), 0)?false:true;
    const bool rhs=equal_eps (m_rhs->Evaluate (errors), 0)?false:true;
    return ((lhs || rhs)?1.:0.);
}

std::pair<double, double> OrNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'||' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> OrNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'||' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void OrNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '||'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
OrNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") || (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Not node
//------------------------------------------------------------------------------

// Constructor
NotNode::NotNode (Expression *expr) : Node (expr), m_rhs (0)
{}

// Destructor
NotNode::~NotNode()
{
    // Free child nodes
    delete m_rhs;
}

// Evaluate
double NotNode::DoEvaluate (ErrorInfo& errors) const
{
    const bool rhs=equal_eps (m_rhs->Evaluate (errors), 0)?false:true;
    return ((!rhs)?1.:0.);
}

std::pair<double, double> NotNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    SHOW_FATAL_ERROR("'!' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

std::pair<double, double> NotNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    SHOW_FATAL_ERROR("'!' is not supported when derivativing it");
    return std::make_pair (0., 0.);
}

// Parse
void NotNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(start != v1 || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("unrecognized symbol neighboring to a '!'");
        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_rhs = right.release();
}

std::string
NotNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("!(" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Negate node
//------------------------------------------------------------------------------

// Constructor
NegateNode::NegateNode (Expression *expr) : Node (expr), m_rhs (0)
{}

// Destructor
NegateNode::~NegateNode()
{
    // Free child nodes
    delete m_rhs;
}

// Evaluate
double NegateNode::DoEvaluate (ErrorInfo& errors) const
{
    return -(m_rhs->Evaluate (errors));
}



std::pair<double, double> NegateNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    std::pair<double, double>result = m_rhs->Evaluate (var_symbol, errors);
    return std::make_pair (-result.first, -result.second);
}

std::pair<double, double> NegateNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    std::pair<double, double>result = m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    return std::make_pair (-result.first, -result.second);
}

// Parse
void NegateNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(start != v1 || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("syntax error");

        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_rhs = right.release();
}

std::string
NegateNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("-(" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Exponent node
//------------------------------------------------------------------------------

// Constructor
ExponentNode::ExponentNode (Expression *expr) : Node (expr), m_lhs (0), m_rhs (0)
{}

// Destructor
ExponentNode::~ExponentNode()
{
    // Free child nodes
    delete m_lhs;
    delete m_rhs;
}

// Evaluate
double ExponentNode::DoEvaluate (ErrorInfo& errors) const
{
    errno = 0;

    double result =  std::pow(m_lhs->Evaluate (errors), m_rhs->Evaluate (errors));

    if(errno)
    {
        errors.add_error(errno, "pow");
    }

    return result;
}



std::pair<double, double> ExponentNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    errno = 0;

    const std::pair<double, double> root  = m_lhs->Evaluate (var_symbol, errors);
    const std::pair<double, double> index = m_rhs->Evaluate (var_symbol, errors);
    const double f   = root.first;
    const double f_x = root.second;
    const double g   = index.first;
    const double g_x = index.second;
    const double value = std::pow(f, g);
    if(errno)
    {
        errors.add_error(errno, "pow");
    }

    /*
     * d (f^g)/dx = d (exp(g*ln (f)))/dx
     * = f^g*(g/f*df/dx+ln (f)dg/dx)
     * = g*f^(g-1)df/dx+ln (f)f^g*dg/dx
     * = f^(g-1)*(g*df/dx + f*ln (f)*dg/dx)
     */
    const double f_g_1=std::pow(f, g - 1.);
    if(errno)
    {
        errors.add_error(errno, "pow");
    }

    double logf = 0.;
    if(!equal_eps (g_x, 0))
    {
        logf = std::log(f);
        if(errno)
        {
            errors.add_error(errno, "pow");
        }
    }

    const double dvalue = f_g_1*(g*f_x + f * logf * g_x);

    return std::make_pair (value, dvalue);
}



std::pair<double, double> ExponentNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    errno = 0;

    const std::pair<double, double> root_2  = m_lhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    const std::pair<double, double> root_11 = m_lhs->Evaluate (var_symbol_1, errors);
    const std::pair<double, double> root_12 = m_lhs->Evaluate (var_symbol_2, errors);

    const std::pair<double, double> index_2  = m_rhs->Evaluate (var_symbol_1, var_symbol_2, errors);
    const std::pair<double, double> index_11 = m_rhs->Evaluate (var_symbol_1, errors);
    const std::pair<double, double> index_12 = m_rhs->Evaluate (var_symbol_2, errors);
    const double f   = root_2.first;
    const double fx  = root_11.second;
    const double fy  = root_12.second;
    const double fxy = root_2.second;

    const double g   = index_2.first;
    const double gx  = index_11.second;
    const double gy  = index_12.second;
    const double gxy = index_2.second;
    const double value = std::pow(f, g);
    if(errno)
    {
        errors.add_error(errno, "pow");
    }

    /*
     * d (f^g)/dxdy = d (exp(g*ln (f)))/dxdy
     * = d/dx*(exp(g*ln (f))*(ln (f)*dg/dy+g/f*df/dy))
     * = f^(g-2)*Q
     * Q = [f*ln (f)dg/dx+g*df/dx]*[f*ln (f)dg/dy+g*df/dy]+
     *     f^2*ln (f)d^2g/dxdy+f*df/dx*dg/dy+f*df/dy*dg/dx+fg*d^2f/dxdy-g*df/dx*df/dy
     */
    const double f_g_2 = std::pow(f, g - 2.);
    if(errno)
    {
        errors.add_error(errno, "pow");
    }
    double lnf = 0.;
    if(!equal_eps (gx, 0) || !equal_eps (gy, 0) || !equal_eps (gxy, 0))
    {
        lnf = std::log(f);
        if(errno)
        {
            errors.add_error(errno, "pow");
        }
    }
    double dvalue = f_g_2*((f*lnf*gx+g*fx) * (f*lnf*gy+g*fy) +
                           f*f*lnf*gxy+f*(fx*gy+fy*gx)+f*g*fxy-g*fx*fy);
    if(errno)
    {
        errors.add_error(errno, "pow");
    }

    return std::make_pair (value, dvalue);
}

// Parse
void ExponentNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    // Check some basic syntax
    if(v1 <= start || v1 >= end)
    {
        SHOW_NONFATAL_ERROR("syntax error");

        good_parse=false;
        return;
    }

    // Parse sides
    std::auto_ptr<Node> left (parser.ParseRegion (start, v1 - 1, good_parse));
    std::auto_ptr<Node> right (parser.ParseRegion (v1 + 1, end, good_parse));

    m_lhs = left.release();
    m_rhs = right.release();
}

std::string
ExponentNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return ("(" + m_lhs->get_renamed_expression (var_map_name) + ") ^ (" + m_rhs->get_renamed_expression (var_map_name) + ")");
}

// Variable node
//------------------------------------------------------------------------------

// Constructor
VariableNode::VariableNode (Expression *expr) :
    Node (expr), m_var(0)
{}

// Destructor
VariableNode::~VariableNode()
{}

// Evaluate
double VariableNode::DoEvaluate (ErrorInfo& errors) const
{
    (void)errors;
    return *m_var;
}



std::pair<double, double> VariableNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)errors;
    if(var_symbol==var_ident)
    {
        return std::make_pair (*m_var, 1.);
    }
    else
    {
        return std::make_pair (*m_var, 0.);
    }
}



std::pair<double, double> VariableNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    return std::make_pair (*m_var, 0.);
}


// Parse
void VariableNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    (void)v1;
    // Check some basic syntax
    if(start != end)
    {
        SHOW_NONFATAL_ERROR("syntax error");

        good_parse=false;
        return;
    }

    // Get value list
    ValueList *vlist = m_expr->GetValueList();
    if(vlist == 0)
    {
        SHOW_NONFATAL_ERROR("no value list");

        good_parse=false;
        return;
    }

    // Get name
    std::string ident = parser[start].GetIdentifier();

    // Get address
    double *vaddr = vlist->GetAddress (ident);

    if(vaddr == 0)
    {
        // If it does not already exist, try to create it
        vlist->Add (ident);
        vaddr = vlist->GetAddress (ident);
    }

    if(vaddr == 0)
    {
        SHOW_NONFATAL_ERROR("not found");

        good_parse=false;
        return;
    }

    // Set information
    m_var = vaddr;
    var_ident=ident;
}

std::string
VariableNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    return (var_map_name + "[\"" + var_ident + "\"]");
}

// Value node
//------------------------------------------------------------------------------

// Constructor
ValueNode::ValueNode (Expression *expr) : Node (expr), m_val(0)
{}

// Destructor
ValueNode::~ValueNode()
{}

// Evaluate
double ValueNode::DoEvaluate (ErrorInfo& errors) const
{
    (void)errors;
    return m_val;
}



std::pair<double, double> ValueNode::DoEvaluate (const std::string& var_symbol, ErrorInfo& errors) const
{
    (void)var_symbol;
    (void)errors;
    return std::make_pair (m_val, 0.);
}



std::pair<double, double> ValueNode::DoEvaluate (const std::string& var_symbol_1, const std::string& var_symbol_2, ErrorInfo& errors) const
{
    (void)var_symbol_1;
    (void)var_symbol_2;
    (void)errors;
    return std::make_pair (m_val, 0.);
}

// Parse
void ValueNode::Parse (
    Parser &parser,
    Parser::size_type start,
    Parser::size_type end,
    Parser::size_type v1,
    bool &good_parse)
{
    (void)v1;
    // Check basic syntax
    if(start != end)
    {
        SHOW_NONFATAL_ERROR("syntax error");

        good_parse=false;
        return;
    }

    // Set info
    m_val = parser[start].GetValue();
}

std::string
ValueNode::get_renamed_expression (
    const std::string& var_map_name) const
{
    (void)var_map_name;
    std::ostringstream oss;
    oss << m_val;
    return oss.str();
}

}
